﻿// Author: AustralTek 
// Creation date: 2012/05/09
// http://www.australtek.com
// Copyright: 2009 - 2012

/* 
Glossary:
*/

(function () {
    try {
        //#region BinarySearch

        var _BinarySearch = { Public: {} };
        _BinarySearch.Base = function (MyReference, ChildBase) {
            try {
                //#region Attributes

                if(!ChildBase)
                    ChildBase = {};

                if(!MyReference.Public)
                    MyReference.Public = {};

                //#region Properties

                MyReference.TransitionSpeed = null;

                MyReference.InitializeOptions = {
                    Events: { /*Click:[],*/ Error: [] }
                    , List: []
                };

                //#endregion

                //#region Methods

                ChildBase.AddContent =
                MyReference.Public.AddContent =
                MyReference.AddContent = function(newContent) {
                    try {
                        if(newContent)
                        {
                            MyReference.ContentContainer.appendChild(newContent);

                            MyReference.UpdateMovingStatus();
                        }
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                };
                ChildBase.Dispose =
                MyReference.Public.Dispose =
                MyReference.Dispose = function() {
                    try {
                        if(MyReference.Container)
                        {
                            FreeRefManager.ReleaseAllReference(MyReference.Container);

                            if(MyReference.GlobalContainer)
                                MyReference.GlobalContainer.removeChild(MyReference.Container);

                            MyReference.Container = null;
                        }
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                };
                ChildBase.DrawContent =
                MyReference.DrawContent = function() {
                    try
                    {
                        MyReference.ContentContainer = document.createElement("div");
                        MyReference.ContentContainer.className = "BinarySearchContentContainer";
                        MyReference.Container.appendChild(MyReference.ContentContainer);

                        setTimeout(MyReference.UpdateMovingStatus, 10);
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                };
                ChildBase.FireEventError =
                MyReference.FireEventError = function(error) {
                    try
                    {
                        for(var handlerIndex = 0; handlerIndex < MyReference.Events.Error.length; handlerIndex++)
                            MyReference.Events.Error[handlerIndex](error, MyReference.Public);
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                };
                ChildBase.GetSpeed =
                MyReference.GetSpeed = function(x) {
                    try
                    {
                        return x + MyReference.MoveAcel;
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                    return x;
                };
                ChildBase.GetMove =
                MyReference.GetMove = function(x) {
                    try
                    {
                        return x + MyReference.MoveSpeed * MyReference.MoveDirection;
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                    return x;
                };
                ChildBase.GetMoveBouncing =
                MyReference.GetMoveBouncing = function(x) {
                    try
                    {
                        return x + /*MyReference.MoveSpeed*/ 1 * MyReference.MoveDirection * -1;
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                    return x;
                };
                ChildBase.GradualMove =
                MyReference.GradualMove = function() {
                    try
                    {
                        if(MyReference.MoveGradualActive == true)
                        {
                            var speedResult = MyReference.TransitionSpeed.Move();
                            var moveResult = MyReference.TransitionPosMove.Move();

                            if((-moveResult.Value <= MyReference.MoveTolerance + MyReference.MoveBouncingMargingLimit) && (-moveResult.Value >= 0))
                            {
                                MyReference.MoveSpeed = speedResult.Value;

                                MyReference.Container.style.marginTop = moveResult.Value.toString() + "px";
                                MyReference.Container.style.paddingBottom = (-moveResult.Value).toString() + "px";

                                if(speedResult.Finished == false)
                                    setTimeout(MyReference.GradualMove, MyReference.MoveGradualTimeout);
                                    
                            }
                            else if(-moveResult.Value <= MyReference.MoveTolerance + MyReference.MoveBouncingMargingLimit)
                            {
                                var currentValue = parseInt(MyReference.Container.style.marginTop);

                                MyReference.TransitionPosBouncing.SetCurrentValue(currentValue);
                                MyReference.TransitionPosBouncing.SetLimitStart(currentValue);
                                MyReference.TransitionPosBouncing.SetLimitEnd(currentValue + MyReference.MoveBouncingMargingLimit * MyReference.MoveDirection * -1);

                                MyReference.GradualMoveBouncing();
                            }
                        }
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                };
                ChildBase.GradualMoveBouncing =
                MyReference.GradualMoveBouncing = function() {
                    try
                    {
                        var moveResult = MyReference.TransitionPosBouncing.Move();

                        if((-moveResult.Value <= MyReference.MoveTolerance + MyReference.MoveBouncingMargingLimit) && (-moveResult.Value >= 0))
                        {
                            MyReference.MoveSpeed = speedResult.Value;

                            MyReference.Container.style.marginTop = moveResult.Value.toString() + "px";
                            MyReference.Container.style.paddingBottom = (-moveResult.Value).toString() + "px";

                            if(speedResult.Finished == false)
                                setTimeout(MyReference.GradualMove, MyReference.MoveGradualTimeout);
                                    
                        }
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                };
                ChildBase.Initialize =
                MyReference.Initialize = function(container, options) {
                    try {
                        MyReference.GlobalContainer = container;

                        /* 
                            For now remove the InitializeOptions struct From MyReference, fill it, isnert it in 
                        MyReference and then add it again.
                        */
                        var initializeOptions = MyReference.InitializeOptions;

                        delete MyReference.InitializeOptions;

                        ParseAttributes.Parse(options, initializeOptions);

                        ParseAttributes.Parse(initializeOptions, MyReference);

                        MyReference.InitializeOptions = initializeOptions;

                        if ((!options) || (!options.Events) || (!options.Events.onError))//Modified this lines when all the events of the ID Widgets will be Arrays.
                            MyReference.Events.Error = [function (error) { window.status = Error.message; } ];
                        if (!MyReference.Events.Error)
                            MyReference.Events.Error = [function (error) { window.status = Error.message; } ];

                        MyReference.TransitionPosMove = new Transition({ FunctionMove: MyReference.GetMove });
                        MyReference.TransitionPosBouncing = new Transition({ FunctionMove: MyReference.GetMoveBouncing });
                        MyReference.TransitionSpeed = new Transition({ FunctionMove: MyReference.GetSpeed });

                        MyReference.IsTouchDevice = ("ontouchstart" in document.documentElement);

                        if(MyReference.IsTouchDevice == false)
                        {
                            MyReference.CommonMoveLimit = 5;
//                            MyReference.MoveDuration = 0.1 * 1000;
//                            MyReference.MoveRangeFactor = 50;
                        }
                        else
                        {
                            MyReference.CommonMoveLimit = 30;
//                            MyReference.MoveDuration = 0.1 * 1000;
//                            MyReference.MoveRangeFactor = 50;
                        }
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                };
                ChildBase.IsChildNodeOf =
                MyReference.IsChildNodeOf = function(parent, childToFind) {
                    try {
                        if (parent.children.length > 0) {
                            for (var iChild = 0; iChild < parent.children.length; iChild++) {
                                if (parent.children[iChild] == childToFind)
                                    return true;
                                else
                                    if (arguments.callee(parent.children[iChild], childToFind) == true)
                                        return true;
                            }
                        }
                    }
                    catch(Error) { MyReference.FireEventError(Error); }
                    return false;
                };
                ChildBase.Redraw =
                MyReference.Redraw = function() {
                    try
                    {
                        MyReference.Dispose();

                        MyReference.Container = document.createElement("div");
                        MyReference.Container.className = "BinarySearchContainer" + " " + MyReference.CSSNotMoving + " " + MyReference.CSSEnableTextSelection;
                        MyReference.GlobalContainer.appendChild(MyReference.Container);

                        MyReference.Container.style.marginTop = 
                        MyReference.Container.style.paddingBottom = 0;

                        if(MyReference.IsTouchDevice == false)
                        {
                            addEventHandler(MyReference.Container, "onmousedown", MyReference.Container_MouseDown);
                            addEventHandler(MyReference.Container, "onmousemove", MyReference.Container_MouseMove);
                            addEventHandler(MyReference.Container, "onmouseout", MyReference.Container_MouseOut);
                            addEventHandler(MyReference.Container, "onmouseup", MyReference.Container_MouseUp);
                        }
                        else
                        {
                            addEventHandler(MyReference.Container, "ontouchstart", MyReference.Container_MouseDown);
                            addEventHandler(MyReference.Container, "ontouchmove", MyReference.Container_MouseMove);                            
                        }

                        addEventHandler(window, "onresize", MyReference.Window_Resize);

                        MyReference.DrawContent();
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                };
                ChildBase.UpdateMovingStatus =
                MyReference.UpdateMovingStatus = function() {
                    try {
                        var containerHeight = ElementSize.GetHeight(MyReference.Container);
                        var contentContainerHeight = ElementSize.GetHeight(MyReference.ContentContainer);
                            
                        MyReference.MoveTolerance = contentContainerHeight - containerHeight;

                        if(MyReference.MoveTolerance > 0)
                        {
                            MyReference.Container.className = MyReference.Container.className.replace(
                                MyReference.CSSNotMoving
                                , MyReference.CSSMoving
                            );
                        }
                        else
                        {
                            MyReference.Container.className = MyReference.Container.className.replace(
                                MyReference.CSSMoving
                                , MyReference.CSSNotMoving
                            );
                        }
                    }
                    catch(Error) { MyReference.FireEventError(Error); }
                };

                //#endregion

                //#region Events

                ChildBase.Container_MouseDown =
                MyReference.Container_MouseDown = function(e) {
                    try
                    {
                        MyReference.MoveGradualActive = false;
                        MyReference.TransitionSpeed.Reset();

                        if(MyReference.MoveTolerance > 0)
                        {
                            var evt = (typeof(e) != "undefined")
                                            ? e
                                            : window.event;

                            MyReference.Position = (MyReference.IsTouchDevice == false)
                                                        ? evt.screenY
                                                        : evt.changedTouches[0].pageY;

                            MyReference.MoveActive = true;
                        }
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                };
                ChildBase.Container_MouseMove =
                MyReference.Container_MouseMove = function(e) {
                    try
                    {
                        if(MyReference.MoveActive == true)
                        {
                            if(MyReference.IsTouchDevice == true)
                                e.preventDefault();

                            var evt = (typeof(e) != "undefined")
                                            ? e
                                            : window.event;
                            var y = (MyReference.IsTouchDevice == false)
                                        ? evt.screenY
                                        : evt.changedTouches[0].pageY;

                            if(MyReference.Position != y)
                            {
                                MyReference.Container.className = MyReference.Container.className.replace(
                                    MyReference.CSSEnableTextSelection
                                    , MyReference.CSSDisableTextSelection
                                );

                                MyReference.MoveRange = MyReference.Position - y;

                                if(MyReference.IsTouchDevice == false)
                                {
                                    var newMarginTop = -(parseInt(MyReference.Container.style.marginTop) - MyReference.MoveRange);

                                    if((newMarginTop <= MyReference.MoveTolerance) && (newMarginTop >= 0))
                                    {
                                        MyReference.Container.style.marginTop = (-newMarginTop).toString() + "px";
                                        MyReference.Container.style.paddingBottom = newMarginTop.toString() + "px";
                                    }
                                }
                                else
                                {
                                    MyReference.MoveActive = false;
                                    MyReference.Position = null;

                                    MyReference.Container.className = MyReference.Container.className.replace(
                                        MyReference.CSSDisableTextSelection
                                        , MyReference.CSSEnableTextSelection
                                    );

                                    MyReference.MoveGradualActive = true;

                                    var currentValue = parseInt(MyReference.Container.style.marginTop);

                                    MyReference.MoveDirection = (MyReference.MoveRange > 0)
                                                                    ? -1 //down
                                                                    : 1 //up

                                    MyReference.MoveSpeed = 
                                        (Math.abs(MyReference.MoveRange) * MyReference.MoveRangeFactor) / MyReference.MoveDuration;

                                    MyReference.TransitionSpeed.SetCurrentValue(currentValue);
                                    MyReference.TransitionSpeed.SetLimitStart(currentValue);
                                    MyReference.TransitionSpeed.SetLimitEnd(currentValue + (-MyReference.MoveRange) * MyReference.MoveRangeFactor);

                                    MyReference.GradualMove();

                                    MyReference.MoveRange = null;
                                }
                            }

                            /* The logic for the touch evnets is not the same for the mouse events. */
                            if(typeof(evt.changedTouches) == "undefined")
                                MyReference.Position = y;
                        }
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                };
                ChildBase.Container_MouseOut =
                MyReference.Container_MouseOut = function(e) {
                    try {
                        var toElement = ((typeof (e) != "undefined") && (e.toElement)) ? e.toElement : e.relatedTarget;

                        if(MyReference.IsChildNodeOf(MyReference.Container, toElement) == false)
                        {
                            MyReference.MoveActive = false;
                            MyReference.Position = null;
                            MyReference.MoveRange = null;

                            MyReference.Container.className = MyReference.Container.className.replace(
                                MyReference.CSSDisableTextSelection
                                , MyReference.CSSEnableTextSelection
                            );
                        }
                    }
                    catch(Error) { MyReference.FireEventError(Error); }
                };
                ChildBase.Container_MouseUp =
                MyReference.Container_MouseUp = function(e) {
                    try
                    {
                        MyReference.MoveActive = false;
                        MyReference.Position = null;

                        MyReference.Container.className = MyReference.Container.className.replace(
                            MyReference.CSSDisableTextSelection
                            , MyReference.CSSEnableTextSelection
                        );

                        if(Math.abs(MyReference.MoveRange) > MyReference.CommonMoveLimit)
                        {
                            MyReference.MoveGradualActive = true;

                            var currentValue = parseInt(MyReference.Container.style.marginTop);

                            MyReference.MoveDirection = (MyReference.MoveRange > 0)
                                                            ? -1
                                                            : 1;

                            MyReference.MoveSpeed = (Math.abs(MyReference.MoveRange) * MyReference.MoveRangeFactor);

                            MyReference.TransitionSpeed.SetCurrentValue(MyReference.MoveSpeed);
                            MyReference.TransitionSpeed.SetLimitStart(MyReference.MoveSpeed);
                            MyReference.TransitionSpeed.SetLimitEnd(0);

                            MyReference.TransitionPosMove.SetCurrentValue(currentValue);
                            MyReference.TransitionPosMove.SetLimitStart(currentValue);
                            MyReference.TransitionPosMove.SetLimitEnd(Infinity * MyReference.MoveDirection);

                            MyReference.GradualMove();
                        }

                        MyReference.MoveRange = null;
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                };
                ChildBase.Window_Resize =
                MyReference.Window_Resize = function(e) {
                    try {
                        MyReference.UpdateMovingStatus();
                    }
                    catch(Error) { MyReference.FireEventError(Error, window.location.href, arguments.callee, ""); }
                };

                //#endregion
            }
            catch(Error) { ShowError(Error.message, window.location.href, arguments.callee, ""); }
        };
        _BinarySearch.Constructor = function (container, options) {
            try {
                var instance = {};
                
                _BinarySearch.Base(instance);

                instance.Initialize(container, options);

                instance.Redraw();

                //#region Public

                //#region Methods

                ObjectExtend(instance.Public, this);

                //#endregion

                //#endregion
            }
            catch(Error) { ShowError(Error.message, window.location.href, arguments.callee, ""); }
        };

        _BinarySearch.Public.Inherit = function(obj) {
            try {
                var childBase = GetLastBaseProperty(obj);

                _BinarySearch.Base(obj, childBase);

                return childBase;
            }
            catch(Error) { ShowError(Error.message, window.location.href, arguments.callee, ""); }
        };

        //#endregion

        window.BinarySearch = _BinarySearch.Constructor;

        ObjectExtend(_BinarySearch.Public, window.BinarySearch);
    }
    catch(Error) { ShowError(Error.message, window.location.href, arguments.callee, ""); }
})();